/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.max.vm.ext.graal.snippets;

import static com.oracle.graal.api.code.MemoryBarriers.*;
import static com.oracle.graal.nodes.extended.MembarNode.*;

import java.util.*;

import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
import com.oracle.graal.replacements.*;
import com.oracle.graal.replacements.Snippet.ConstantParameter;
import com.oracle.graal.replacements.SnippetTemplate.*;
import com.oracle.max.vm.ext.graal.*;
import com.oracle.max.vm.ext.graal.nodes.*;
import com.sun.cri.ci.*;
import com.sun.cri.ri.*;
import com.sun.max.annotate.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.classfile.constant.*;
import com.sun.max.vm.compiler.*;
import com.sun.max.vm.object.*;
import com.sun.max.vm.runtime.*;
import com.sun.max.vm.runtime.Snippets;

/**
 * Snippets for field access, resolved and unresolved. The unresolved field lowerings use similar code
 * generated by {@link T1X} and makes a runtime call to do the resolution. Ideally, the code
 * sequences would be shared, however, {@code T1X} does not do volatile handling in the template for
 * resolved fields (for some reason) and also uses {@code int} and casts for {@code boolean, byte, char, short} types
 * in the templates.
 *
 * When deoptimzation for Graal works, it might be better to follow the normal Graal expectation of deoptimizing the code
 * for unresolved fields, thus leaving the resolution to {@link T1X}.
 *
 * One possible improvement to unresolved field handling would be to inline the guard check.
 *
 * The resolved snippets are very simple and actually the same for instance fields and static fields,
 * as either the static tuple or the receiver is passed as the "object", so the signatures are identical.
 * However, whereas static tuples are guaranteed non-null by the VM, normal object references are not,
 * so need null checking. N.B. most null checks are eliminated and handled by hardware (implicit) exceptions.
 *
 * Unresolved snippets are more complex, as we can't access the static tuple until the resolution has occurred,
 * and the runtime calls in the (historic) {@link Snippets} class to do the resolution are different for static
 * and instance fields. So there are separate snippets for instance and static fields. There is also an intermediate
 * state where a static field is resolved but the class may need to be initialized.
 *
 * Once the resolution/init is done, the resolved snippet can be invoked (as runtime code) to handle the field access.
 *
 * A note on naming. Although the bytecode names are {@code GET/PUT}, Graal uses {@code Load/Store} and does not distinguish static
 * loads by name, instead by the receiver field being {@code null}. We follow the Graal naming for the classes
 * that effect the lowering, but use the bytecode style names for the actual snippets and runtime entry methods.
 * Further we consistently use {@code Get#MODE#Field} where, {@code #MODE} is either {@code Instance} or {@code Static}.
 *
 * The {@code Object} field load/store operations may, depending on the {@link HeapScheme} in use, involve read/write
 * barriers. These may themselves involve loading fields from objects controlled by the {@link HeapScheme}, that
 * may be {@link CONSTANT_WHEN_NOT_ZERO} at runtime. The resolved field lowering handles this situation explicitly but there
 * is evidently an opportunity to transform the snippet on VM startup to replace the field access with the runtime constant.
 */
public class FieldSnippets extends SnippetLowerings {

    @HOSTED_ONLY
    public FieldSnippets(MetaAccessProvider runtime, Replacements replacements, TargetDescription targetDescription, Map<Class< ? extends Node>, LoweringProvider> lowerings) {
        super(runtime, replacements, targetDescription);
    }

    @Override
    @HOSTED_ONLY
    public void registerLowerings(MetaAccessProvider runtime, Replacements replacements, TargetDescription targetDescription, Map<Class< ? extends Node>, LoweringProvider> lowerings) {
        LoadFieldLowering loadFieldLowering = new LoadFieldLowering();
        StoreFieldLowering storeFieldLowering = new StoreFieldLowering();

        UnresolvedLoadFieldLowering unresolvedLoadFieldLowering = new UnresolvedLoadFieldLowering();
        UnresolvedStoreFieldLowering unresolvedStoreFieldLowering = new UnresolvedStoreFieldLowering();

        addSnippets(loadFieldLowering, storeFieldLowering, unresolvedLoadFieldLowering, unresolvedStoreFieldLowering);

        lowerings.put(LoadFieldNode.class, loadFieldLowering);
        lowerings.put(StoreFieldNode.class, storeFieldLowering);

        lowerings.put(ResolveFieldNode.class, new ResolveFieldLowering());
        lowerings.put(UnresolvedLoadFieldNode.class, unresolvedLoadFieldLowering);
        lowerings.put(UnresolvedStoreFieldNode.class, unresolvedStoreFieldLowering);
    }

    protected abstract class FieldLowering extends Lowering {
        protected final SnippetInfo[] snippets = new SnippetInfo[Kind.values().length];

        void setSnippet(Kind kind, SnippetInfo snippet) {
            snippets[kind.ordinal()] = snippet;
        }
    }

    protected abstract class ResolvedFieldLowering extends FieldLowering {

        void lower(AccessFieldNode node, LoweringTool tool) {
            FieldActor fieldActor = (FieldActor) MaxResolvedJavaField.getRiResolvedField(node.field());
            /*
             * Check for access to fields that are CONSTANT_WHEN_NOT_ZERO with a constant receiver.
             * Most important for the biasedtableAddress of the CardTable for GenSSHeapScheme
             * May not be the best place to do this.
             */
            if (fieldActor.isConstantWhenNotZero() && node.object() != null && node.object().isConstant() &&
                            node.object().asConstant().isNonNull()) {
                CiConstant value = fieldActor.constantValue(ConstantMap.toCi(node.object().asConstant()));
                if (value != null) {
                    StructuredGraph graph = node.graph();
                    node.replaceAndDelete(graph.add(ConstantNode.forConstant(ConstantMap.toGraal(value), runtime, graph)));
                    return;
                }
            }
            boolean isStatic = node.isStatic();
            Arguments args = new Arguments(snippets[KindMap.toGraalKind(WordUtil.ciKind(fieldActor.kind, true)).ordinal()]);
            args.add("object", isStatic ? fieldActor.holder().staticTuple() : node.object());
            args.add("offset", fieldActor.offset());
            args.addConst("isStatic", isStatic);
            args.addConst("isVolatile", fieldActor.isVolatile());
            storeFieldArg(node, args);
            instantiate(node, args, tool);
        }

        protected void storeFieldArg(AccessFieldNode node, Arguments args) {
        }

    }

    protected class LoadFieldLowering extends ResolvedFieldLowering implements LoweringProvider<LoadFieldNode> {

        @Override
        public void lower(LoadFieldNode node, LoweringTool tool) {
            super.lower(node, tool);
        }

    }

    protected class StoreFieldLowering extends ResolvedFieldLowering implements LoweringProvider<StoreFieldNode> {

        @Override
        public void lower(StoreFieldNode node, LoweringTool tool) {
            super.lower(node, tool);
        }

        @Override
        protected void storeFieldArg(AccessFieldNode node, Arguments args) {
            args.add("value", ((StoreFieldNode) node).value());
        }
    }

    /**
     * The lowering necessary to resolve an unresolved field.
     */
    protected class ResolveFieldLowering extends Lowering implements LoweringProvider<ResolveFieldNode> {

        private final SnippetInfo makeHolderInitializedSnippet;
        private final SnippetInfo resolveInstanceForReadingSnippet;
        private final SnippetInfo resolveStaticForReadingSnippet;
        private final SnippetInfo resolveInstanceForWritingSnippet;
        private final SnippetInfo resolveStaticForWritingSnippet;
        private final SnippetInfo resolvedSnippet;

        @HOSTED_ONLY
        protected ResolveFieldLowering() {
            makeHolderInitializedSnippet = snippet(FieldSnippets.class, "makeHolderInitializedSnippet");
            resolveInstanceForReadingSnippet = snippet(FieldSnippets.class, "resolveInstanceForReadingSnippet");
            resolveStaticForReadingSnippet = snippet(FieldSnippets.class, "resolveStaticForReadingSnippet");
            resolveInstanceForWritingSnippet = snippet(FieldSnippets.class, "resolveInstanceForWritingSnippet");
            resolveStaticForWritingSnippet = snippet(FieldSnippets.class, "resolveStaticForWritingSnippet");
            resolvedSnippet = snippet(FieldSnippets.class, "resolvedSnippet");
        }

        public void lower(ResolveFieldNode node, LoweringTool tool) {
            Arguments args;
            boolean isStatic = node.isStatic();
            RiField riField = MaxJavaField.getRiField(node.javaField());
            // N.B. May have resolved by the time we get here!
            if (riField instanceof FieldActor) {
               // resolved but may need class initialization if static
                if (isStatic) {
                    args = new Arguments(makeHolderInitializedSnippet);
                } else {
                    args = new Arguments(resolvedSnippet);
                }
                args.add("fieldActor", riField);
            } else {
                UnresolvedField unresolvedField = (UnresolvedField) riField;
                ResolutionGuard.InPool guard = unresolvedField.constantPool.makeResolutionGuard(unresolvedField.cpi);
                SnippetInfo snippetInfo = node.isLoad() ? (isStatic ? resolveStaticForReadingSnippet : resolveInstanceForReadingSnippet) :
                                                          (isStatic ? resolveStaticForWritingSnippet : resolveInstanceForWritingSnippet);
                args = new Arguments(snippetInfo);
                args.add("guard", guard);
            }
            instantiate(node, args, tool);
        }

    }

    protected class UnresolvedFieldLowering extends FieldLowering {

        void lower(UnresolvedAccessFieldNode node, LoweringTool tool) {
            ValueNode fieldActor = node.resolvedFieldActor();
            Arguments args = new Arguments(snippets[node.javaField().getKind().ordinal()]);
            args.add("object", node.object());
            args.addConst("isStatic", node.isStatic());
            args.add("fieldActor", fieldActor);
            storeFieldArg(node, args);
            instantiate(node, args, tool);
        }

        protected void storeFieldArg(UnresolvedAccessFieldNode node, Arguments args) {
        }

    }

    protected class UnresolvedLoadFieldLowering extends UnresolvedFieldLowering implements LoweringProvider<UnresolvedLoadFieldNode> {

        @Override
        public void lower(UnresolvedLoadFieldNode node, LoweringTool tool) {
            super.lower(node, tool);
        }

    }

    protected class UnresolvedStoreFieldLowering extends UnresolvedFieldLowering implements LoweringProvider<UnresolvedStoreFieldNode> {

        @Override
        public void lower(UnresolvedStoreFieldNode node, LoweringTool tool) {
            super.lower(node, tool);
        }

        @Override
        protected void storeFieldArg(UnresolvedAccessFieldNode node, Arguments args) {
            args.add("value", ((UnresolvedStoreFieldNode) node).value());
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static FieldActor resolveInstanceForReadingSnippet(ResolutionGuard.InPool guard) {
        return Snippets.resolveInstanceFieldForReading(guard);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static FieldActor resolveInstanceForWritingSnippet(ResolutionGuard.InPool guard) {
        return Snippets.resolveInstanceFieldForWriting(guard);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static FieldActor resolveStaticForReadingSnippet(ResolutionGuard.InPool guard) {
        FieldActor fieldActor = Snippets.resolveStaticFieldForReading(guard);
        Snippets.makeHolderInitialized(fieldActor);
        return fieldActor;
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static FieldActor resolveStaticForWritingSnippet(ResolutionGuard.InPool guard) {
        FieldActor fieldActor = Snippets.resolveStaticFieldForWriting(guard);
        Snippets.makeHolderInitialized(fieldActor);
        return fieldActor;
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static FieldActor makeHolderInitializedSnippet(FieldActor fieldActor) {
        Snippets.makeHolderInitialized(fieldActor);
        return fieldActor;
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static FieldActor resolvedSnippet(FieldActor fieldActor) {
        return fieldActor;
    }

// START GENERATED CODE
    @INLINE
    private static boolean getFieldBoolean(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        boolean result = TupleAccess.readBoolean(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldBoolean(Object object, boolean nullCheck, int offset, boolean isVolatile, boolean value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeBoolean(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static boolean getFieldBooleanSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return getFieldBoolean(object, !isStatic, offset, isVolatile);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldBooleanSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, boolean value) {
        putFieldBoolean(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static boolean getUnresolvedFieldBooleanSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return getFieldBoolean(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldBooleanSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, boolean value) {
        putFieldBoolean(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @INLINE
    private static byte getFieldByte(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        byte result = TupleAccess.readByte(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldByte(Object object, boolean nullCheck, int offset, boolean isVolatile, byte value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeByte(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static byte getFieldByteSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return getFieldByte(object, !isStatic, offset, isVolatile);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldByteSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, byte value) {
        putFieldByte(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static byte getUnresolvedFieldByteSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return getFieldByte(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldByteSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, byte value) {
        putFieldByte(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @INLINE
    private static short getFieldShort(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        short result = TupleAccess.readShort(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldShort(Object object, boolean nullCheck, int offset, boolean isVolatile, short value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeShort(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static short getFieldShortSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return getFieldShort(object, !isStatic, offset, isVolatile);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldShortSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, short value) {
        putFieldShort(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static short getUnresolvedFieldShortSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return getFieldShort(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldShortSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, short value) {
        putFieldShort(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @INLINE
    private static char getFieldChar(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        char result = TupleAccess.readChar(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldChar(Object object, boolean nullCheck, int offset, boolean isVolatile, char value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeChar(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static char getFieldCharSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return getFieldChar(object, !isStatic, offset, isVolatile);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldCharSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, char value) {
        putFieldChar(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static char getUnresolvedFieldCharSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return getFieldChar(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldCharSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, char value) {
        putFieldChar(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @INLINE
    private static int getFieldInt(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        int result = TupleAccess.readInt(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldInt(Object object, boolean nullCheck, int offset, boolean isVolatile, int value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeInt(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static int getFieldIntSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return getFieldInt(object, !isStatic, offset, isVolatile);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldIntSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, int value) {
        putFieldInt(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static int getUnresolvedFieldIntSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return getFieldInt(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldIntSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, int value) {
        putFieldInt(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @INLINE
    private static float getFieldFloat(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        float result = TupleAccess.readFloat(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldFloat(Object object, boolean nullCheck, int offset, boolean isVolatile, float value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeFloat(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static float getFieldFloatSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return getFieldFloat(object, !isStatic, offset, isVolatile);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldFloatSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, float value) {
        putFieldFloat(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static float getUnresolvedFieldFloatSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return getFieldFloat(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldFloatSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, float value) {
        putFieldFloat(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @INLINE
    private static long getFieldLong(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        long result = TupleAccess.readLong(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldLong(Object object, boolean nullCheck, int offset, boolean isVolatile, long value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeLong(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static long getFieldLongSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return getFieldLong(object, !isStatic, offset, isVolatile);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldLongSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, long value) {
        putFieldLong(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static long getUnresolvedFieldLongSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return getFieldLong(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldLongSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, long value) {
        putFieldLong(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @INLINE
    private static double getFieldDouble(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        double result = TupleAccess.readDouble(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldDouble(Object object, boolean nullCheck, int offset, boolean isVolatile, double value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeDouble(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static double getFieldDoubleSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return getFieldDouble(object, !isStatic, offset, isVolatile);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldDoubleSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, double value) {
        putFieldDouble(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static double getUnresolvedFieldDoubleSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return getFieldDouble(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldDoubleSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, double value) {
        putFieldDouble(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @INLINE
    private static Object getFieldObject(Object object, boolean nullCheck, int offset, boolean isVolatile) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_READ);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        Object result = TupleAccess.readObject(object, offset);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
        return result;
    }

    @INLINE
    private static void putFieldObject(Object object, boolean nullCheck, int offset, boolean isVolatile, Object value) {
        if (isVolatile) {
            memoryBarrier(JMM_PRE_VOLATILE_WRITE);
        }
        if (nullCheck) {
            MaxNullCheckNode.nullCheck(object);
        }
        TupleAccess.writeObject(object, offset, value);
        if (isVolatile) {
            memoryBarrier(JMM_POST_VOLATILE_READ);
        }
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static Object getFieldObjectSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile) {
        return UnsafeCastNode.unsafeCast(getFieldObject(object, !isStatic, offset, isVolatile), StampFactory.forNodeIntrinsic());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putFieldObjectSnippet(Object object, int offset, @ConstantParameter boolean isStatic, @ConstantParameter boolean isVolatile, Object value) {
        putFieldObject(object, !isStatic, offset, isVolatile, value);
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static Object getUnresolvedFieldObjectSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor) {
        return UnsafeCastNode.unsafeCast(getFieldObject(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile()), StampFactory.forNodeIntrinsic());
    }

    @Snippet(inlining = MaxSnippetInliningPolicy.class)
    private static void putUnresolvedFieldObjectSnippet(Object object, @ConstantParameter boolean isStatic, FieldActor fieldActor, Object value) {
        putFieldObject(isStatic ? fieldActor.holder().staticTuple() : object, !isStatic, fieldActor.offset(), fieldActor.isVolatile(), value);
    }

    @HOSTED_ONLY
    private void addSnippets(
            LoadFieldLowering loadFieldLowering, StoreFieldLowering storeFieldLowering,
            UnresolvedLoadFieldLowering loadUnresolvedFieldLowering, UnresolvedStoreFieldLowering storeUnresolvedFieldLowering) {
        loadFieldLowering.setSnippet(Kind.Boolean, snippet(FieldSnippets.class, "getFieldBooleanSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Boolean, snippet(FieldSnippets.class, "getUnresolvedFieldBooleanSnippet"));
        storeFieldLowering.setSnippet(Kind.Boolean, snippet(FieldSnippets.class, "putFieldBooleanSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Boolean, snippet(FieldSnippets.class, "putUnresolvedFieldBooleanSnippet"));
        loadFieldLowering.setSnippet(Kind.Byte, snippet(FieldSnippets.class, "getFieldByteSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Byte, snippet(FieldSnippets.class, "getUnresolvedFieldByteSnippet"));
        storeFieldLowering.setSnippet(Kind.Byte, snippet(FieldSnippets.class, "putFieldByteSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Byte, snippet(FieldSnippets.class, "putUnresolvedFieldByteSnippet"));
        loadFieldLowering.setSnippet(Kind.Short, snippet(FieldSnippets.class, "getFieldShortSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Short, snippet(FieldSnippets.class, "getUnresolvedFieldShortSnippet"));
        storeFieldLowering.setSnippet(Kind.Short, snippet(FieldSnippets.class, "putFieldShortSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Short, snippet(FieldSnippets.class, "putUnresolvedFieldShortSnippet"));
        loadFieldLowering.setSnippet(Kind.Char, snippet(FieldSnippets.class, "getFieldCharSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Char, snippet(FieldSnippets.class, "getUnresolvedFieldCharSnippet"));
        storeFieldLowering.setSnippet(Kind.Char, snippet(FieldSnippets.class, "putFieldCharSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Char, snippet(FieldSnippets.class, "putUnresolvedFieldCharSnippet"));
        loadFieldLowering.setSnippet(Kind.Int, snippet(FieldSnippets.class, "getFieldIntSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Int, snippet(FieldSnippets.class, "getUnresolvedFieldIntSnippet"));
        storeFieldLowering.setSnippet(Kind.Int, snippet(FieldSnippets.class, "putFieldIntSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Int, snippet(FieldSnippets.class, "putUnresolvedFieldIntSnippet"));
        loadFieldLowering.setSnippet(Kind.Float, snippet(FieldSnippets.class, "getFieldFloatSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Float, snippet(FieldSnippets.class, "getUnresolvedFieldFloatSnippet"));
        storeFieldLowering.setSnippet(Kind.Float, snippet(FieldSnippets.class, "putFieldFloatSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Float, snippet(FieldSnippets.class, "putUnresolvedFieldFloatSnippet"));
        loadFieldLowering.setSnippet(Kind.Long, snippet(FieldSnippets.class, "getFieldLongSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Long, snippet(FieldSnippets.class, "getUnresolvedFieldLongSnippet"));
        storeFieldLowering.setSnippet(Kind.Long, snippet(FieldSnippets.class, "putFieldLongSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Long, snippet(FieldSnippets.class, "putUnresolvedFieldLongSnippet"));
        loadFieldLowering.setSnippet(Kind.Double, snippet(FieldSnippets.class, "getFieldDoubleSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Double, snippet(FieldSnippets.class, "getUnresolvedFieldDoubleSnippet"));
        storeFieldLowering.setSnippet(Kind.Double, snippet(FieldSnippets.class, "putFieldDoubleSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Double, snippet(FieldSnippets.class, "putUnresolvedFieldDoubleSnippet"));
        loadFieldLowering.setSnippet(Kind.Object, snippet(FieldSnippets.class, "getFieldObjectSnippet"));
        loadUnresolvedFieldLowering.setSnippet(Kind.Object, snippet(FieldSnippets.class, "getUnresolvedFieldObjectSnippet"));
        storeFieldLowering.setSnippet(Kind.Object, snippet(FieldSnippets.class, "putFieldObjectSnippet"));
        storeUnresolvedFieldLowering.setSnippet(Kind.Object, snippet(FieldSnippets.class, "putUnresolvedFieldObjectSnippet"));
    }
// END GENERATED CODE

}
